package com.noahsloan.nutils.bytes;

import static java.lang.System.in;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;

/**
 * Utility for converting hexadecimal strings into bytes.
 * 
 * @author noah
 * 
 */
public class Hex2Bytes {

    /**
     * @param args
     *            1, (optional) character encoding
     * @throws IOException
     */
    public static void main(String[] args) throws IOException {
        Reader r;
        try {
            r = (args.length > 0) ? new InputStreamReader(in, args[0])
                    : new InputStreamReader(in);
        } catch (UnsupportedEncodingException e) {
            System.err.printf("%s is not a valid text encoding.", args[0]);
            return;
        }
        char[] c;
        while ((c = getByte(r)) != null) {
            System.out.write(convert(c));
        }
        System.out.close();
    }

    /**
     * Gets 2 characters from the reader, i.e. 1 byte in hex.
     * 
     * @param r
     * @return
     * @throws IOException
     */
    protected static char[] getByte(Reader r) throws IOException {
        int[] c = { r.read(), r.read() };
        if (c[0] < 0 || c[1] < 0) {
            return null;
        }
        return new char[] { (char) c[0], (char) c[1] };
    }

    /**
     * 
     * @param c
     *            a 2 character array to convert
     * @return the byte value of the 2 character hex code
     */
    public static int convert(char[] c) {
        return convert(c[0]) * 16 + convert(c[1]);
    }

    /**
     * Convert a single hex character. Note that it takes 2 hex characters to
     * make a full byte.
     * 
     * @param c
     * @return
     */
    protected static int convert(char c) {
        if (c >= '0' && c <= '9') {
            return c - '0';
        } else {
            return Character.toUpperCase(c) - 'A' + 10;
        }
    }

    /**
     * 
     * @param s
     *            the string to convert
     * @return the value in bytes
     */
    public static byte[] convert(String s) {
        byte[] bytes = new byte[s.length() / 2];
        for (int i = 0; i < bytes.length; i++) {
            bytes[i] = (byte) convert(s.substring(i * 2, i * 2 + 2)
                    .toCharArray());
        }
        return bytes;
    }
}
